using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using DirectShowLib;
using LeisureCenter.Api;

namespace DirectShowPlayer
{
    public class DirectShowControl : Control
    {
        public const int WMGraphNotify = 0x0400 + 13;

        private DirectShowVideoMedia owner;

        public DirectShowControl(DirectShowVideoMedia owner)
            : base()
        {
            this.owner = owner;
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WMGraphNotify:
                    {
                        this.owner.HandleGraphEvent();
                        break;
                    }
            }

            // Pass this message to the video window for notification of system changes
            if (this.owner.videoWindow != null)
                this.owner.videoWindow.NotifyOwnerMessage(m.HWnd, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());

            base.WndProc(ref m);
        }
    }

    public class DirectShowVideoMedia : BaseDirectShowMedia, IVisualMedia, ISearchableMedia
    {
        public IVideoWindow videoWindow;
        private Rectangle previewArea = new Rectangle(0, 0, 500, 400);
        private Control previewControl;
        protected Form fullScreenForm;
        protected DirectShowControl control;

        protected bool fullScreen;
        private double playRate = 1;
        private int savedVolume;

        public DirectShowVideoMedia(DirectShowPlayer player, string fileName)
            : base(player, fileName)
        {
            this.control = new DirectShowControl(this);
            this.control.DoubleClick += new EventHandler(control_DoubleClick);
        }

        void control_DoubleClick(object sender, EventArgs e)
        {
            this.player.plugin.leisureCenterInstance.CommandsManager.EnqueueCommand(LeisureCenterCommand.ToggleFullScreen);
        }

        public void HandleGraphEvent()
        {
            int hr = 0;
            EventCode evCode;
            int evParam1, evParam2;

            // Process all queued events
            while (this.mediaEventEx != null && this.mediaEventEx.GetEvent(out evCode, out evParam1, out evParam2, 0) == 0)
            {
                // Free memory associated with callback, since we're not using it
                hr = this.mediaEventEx.FreeEventParams(evCode, evParam1, evParam2);

                // If this is the end of the clip, reset to beginning
                if (evCode == EventCode.Complete)
                {
                    OnMediaEnded();
                }
            }
        }

        protected override void CloseInterfaces()
        {
            int hr = 0;

            // Relinquish ownership (IMPORTANT!) after hiding video window
            hr = this.videoWindow.put_Visible(OABool.False);
            DsError.ThrowExceptionForHR(hr);
            hr = this.videoWindow.put_Owner(IntPtr.Zero);
            DsError.ThrowExceptionForHR(hr);

            if (this.videoWindow != null)
                this.videoWindow = null;

            base.CloseInterfaces();
        }

        protected override void OpenFile()
        {
            playRate = 1.0;
            fullScreen = false;

            base.OpenFile();

            try
            {
                int hr = 0;

                // Query for video interfaces, which may not be relevant for audio files
                this.videoWindow = this.graphBuilder as IVideoWindow;
                this.basicVideo = this.graphBuilder as IBasicVideo;

                /*                // Setup the video window
                                hr = this.videoWindow.put_Owner(this.Handle);
                                DsError.ThrowExceptionForHR(hr);*/
                hr = this.mediaEventEx.SetNotifyWindow(this.control.Handle, DirectShowControl.WMGraphNotify, IntPtr.Zero);
                DsError.ThrowExceptionForHR(hr);

                hr = this.videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings | WindowStyle.ClipChildren);
                DsError.ThrowExceptionForHR(hr);

                hr = this.videoWindow.put_MessageDrain(control.Handle);
                DsError.ThrowExceptionForHR(hr);

                PlaceVideoWindow();
                DsError.ThrowExceptionForHR(hr);
            }
            catch (Exception ex)
            {
                LoadingState = MediaLoadingState.Error;
                loadingErrorMessage = ex.Message;
            }
        }

        protected override void DoPlay()
        {
            base.DoPlay();
            if (PlayRate != 1)
                PlayRate = 1;
        }

        protected override void DoStop()
        {
            if (videoWindow != null)
            {
                FullScreen = false;
            }
            base.DoStop();
        }

        private void PlaceVideoWindow(Control owner, Rectangle area)
        {
            int hr = 0;
            int lHeight, lWidth;

            if (videoWindow == null)
                return;

            //videoWindow.put_FullScreenMode(OABool.False);

            if (previewControl != null)
                videoWindow.put_Owner(owner.Handle);

            if (this.basicVideo == null)
                return;

            // Read the default video size
            hr = this.basicVideo.GetVideoSize(out lWidth, out lHeight);
            if (hr == DsResults.E_NoInterface)
                return;

            double ratio = (double)area.Height / (double)lHeight;
            ratio = Math.Min((double)area.Width / (double)lWidth, ratio);

            lWidth = (int)(lWidth * ratio);
            lHeight = (int)(lHeight * ratio);

            if (owner != null)
            {
                videoWindow.SetWindowPosition(
                    (area.Width - lWidth) / 2,
                    (area.Height - lHeight) / 2,
                    lWidth, lHeight);
            }
            else
            {
                videoWindow.SetWindowPosition(
                    area.Left + (area.Width - lWidth) / 2,
                    area.Top + (area.Height - lHeight) / 2,
                    lWidth, lHeight);
            }
        }

        private void PlaceVideoWindow()
        {
            if (fullScreen)
            {
                if (this.fullScreenForm == null)
                {
                    CreateFullScreenForm();
                }
                if (!this.fullScreenForm.Visible)
                    this.fullScreenForm.Show();
                //videoWindow.put_FullScreenMode(OABool.True);
                PlaceVideoWindow(this.fullScreenForm, new Rectangle(0, 0, this.fullScreenForm.Width, this.fullScreenForm.Height));
            }
            else
            {
                if (this.fullScreenForm != null)
                    this.fullScreenForm.Hide();
                PlaceVideoWindow(previewControl, previewArea);
            }
        }

        protected virtual void CreateFullScreenForm()
        {
            this.fullScreenForm = new Form();
            this.fullScreenForm.BackColor = Color.Black;
            this.fullScreenForm.FormBorderStyle = FormBorderStyle.None;
            this.fullScreenForm.WindowState = FormWindowState.Maximized;
            this.fullScreenForm.TopMost = true;
        }

        #region IVisualMedia Membres

        public bool FullScreen
        {
            get { return this.fullScreenForm != null && this.fullScreenForm.Visible; }
            set
            {
                fullScreen = value;
                PlaceVideoWindow();
            }
        }

        public MediaAspectRatio AspectRatio
        {
            get
            {
                throw new Exception("The method or operation is not implemented.");
            }
            set
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }

        public void SetPreviewArea(Control control, Rectangle rect)
        {
            previewArea = rect;
            previewControl = control;
            PlaceVideoWindow();
            if (videoWindow != null)
                videoWindow.put_Visible(OABool.True);
        }

        public void HidePreview()
        {
            if (videoWindow != null)
                videoWindow.put_Visible(OABool.False);
        }

        #endregion

        #region ISearchableMedia Membres

        public double PlayRate
        {
            get { return playRate; }
            set
            {
                double newPlayRate;
                this._mediaSeeking.SetRate(value);
                this._mediaSeeking.GetRate(out newPlayRate);
                if (newPlayRate != this.playRate)
                {
                    if (this.playRate == 1)
                        this.basicAudio.get_Volume(out this.savedVolume);
                    this.playRate = newPlayRate;
                    if (this.playRate == 1)
                        this.basicAudio.put_Volume(this.savedVolume);
                }
            }
        }

        public void FastForward()
        {
            if (this.playRate < 0)
                PlayRate = 2;
            else
                PlayRate *= 2;
        }

        public void FastReverse()
        {
            if (_mediaSeeking != null)
            {
                AMSeekingSeekingCapabilities capabilities;
                _mediaSeeking.GetCapabilities(out capabilities);
                if ((capabilities & AMSeekingSeekingCapabilities.CanSeekBackwards) > 0)
                {
                    if (this.playRate > 0)
                        PlayRate = -2;
                    else
                        PlayRate *= 2;
                }
            }
        }

        #endregion
    }
}
